(ns fx-clj.generator.generate
  (:require [clojure.java.io :as io]
            [clojure.pprint :refer [pprint]]
            [org.tobereplaced.lettercase :as l])
  (:import (javafx.scene.control.cell CheckBoxTreeCell CheckBoxTreeTableCell
                                      CheckBoxTableCell CheckBoxListCell
                                      ChoiceBoxListCell ChoiceBoxTableCell
                                      ChoiceBoxTreeCell ChoiceBoxTreeTableCell
                                      TextFieldTreeTableCell TextFieldTreeCell
                                      ProgressBarTableCell
                                      ProgressBarTreeTableCell
                                      ComboBoxTreeTableCell ComboBoxTreeCell
                                      ComboBoxTableCell ComboBoxListCell
                                      TextFieldListCell TextFieldTableCell)
           (javafx.scene.control CheckMenuItem ButtonBase Button Accordion Cell
                                 CheckBox ChoiceBox ColorPicker ComboBox
                                 ComboBoxBase TextField TreeView TreeTableView
                                 TreeTableRow TreeTableColumn TreeTableCell
                                 TreeCell Tooltip ToolBar ToggleButton
                                 TitledPane TextInputControl ProgressBar
                                 ProgressIndicator PopupControl PasswordField
                                 Pagination MenuItem MenuButton MenuBar Menu
                                 ListView ListCell Labeled Label IndexedCell
                                 Hyperlink DatePicker DateCell CustomMenuItem
                                 Control ContextMenu RadioButton RadioMenuItem
                                 ScrollBar ScrollPane Separator
                                 SeparatorMenuItem Slider SplitMenuButton
                                 SplitPane Tab TableCell TableColumn
                                 TableColumnBase TableRow TableView TabPane
                                 TextArea TreeItem ToggleGroup)
           (javafx.scene.chart BarChart Axis AreaChart BubbleChart CategoryAxis
                               Chart XYChart ValueAxis PieChart NumberAxis
                               LineChart ScatterChart StackedAreaChart
                               StackedBarChart)
           (javafx.scene.layout BorderPane AnchorPane VBox TilePane Pane HBox
                                GridPane FlowPane Region StackPane RowConstraints ColumnConstraints)
           (javafx.scene.shape Arc Box Circle Polyline Polygon Path MeshView
                               Line Ellipse Cylinder CubicCurve QuadCurve
                               Rectangle Shape Shape3D Sphere SVGPath)
           (javafx.scene AmbientLight Camera PointLight PerspectiveCamera
                         Parent ParallelCamera Node LightBase Group SubScene)
           (javafx.scene.canvas Canvas)
           (javafx.scene.web WebView HTMLEditor)
           (javafx.scene.text TextFlow Text)
           (javafx.scene.media MediaView)
           (javafx.scene.image ImageView)
           (javafx.embed.swing SwingNode)
           (javafx.stage PopupWindow Stage Popup DirectoryChooser FileChooser)
           (javafx.animation TranslateTransition FadeTransition FillTransition ParallelTransition PathTransition PauseTransition RotateTransition ScaleTransition SequentialTransition StrokeTransition Timeline KeyFrame KeyValue)))

(def styleable-classes
  [Accordion, AmbientLight, AnchorPane, Arc, AreaChart, Axis,
   BarChart, BorderPane, Box, BubbleChart, Button, #_ButtonBase,
   Camera, Canvas, CategoryAxis, Cell, Chart, CheckBox,
   CheckBoxListCell, CheckBoxTableCell, CheckBoxTreeCell,
   CheckBoxTreeTableCell, CheckMenuItem, ChoiceBox,
   ChoiceBoxListCell, ChoiceBoxTableCell, ChoiceBoxTreeCell,
   ChoiceBoxTreeTableCell, Circle, ColorPicker, ComboBox,
   ComboBoxBase, ComboBoxListCell, ComboBoxTableCell,
   ComboBoxTreeCell, ComboBoxTreeTableCell, ContextMenu, Control,
   CubicCurve, CustomMenuItem, Cylinder, DateCell, DatePicker,
   Ellipse, FlowPane, GridPane, Group, HBox, HTMLEditor, Hyperlink,
   ImageView, IndexedCell, Label, Labeled, LightBase, Line,
   LineChart, ListCell, ListView, MediaView, Menu, MenuBar,
   MenuButton, MenuItem, MeshView, Node, NumberAxis,
   ;; Pagination,
   Pane, ParallelCamera, Parent, PasswordField, Path,
   PerspectiveCamera, PieChart, PointLight, Polygon, Polyline,
   PopupControl,
   ;; PopupControl.CSSBridge,
   ProgressBar,
   ProgressBarTableCell, ProgressBarTreeTableCell, ProgressIndicator,
   QuadCurve, RadioButton, RadioMenuItem, Rectangle, Region,
   ScatterChart, ScrollBar, ScrollPane, Separator, SeparatorMenuItem,
   Shape, Shape3D, Slider, Sphere, SplitMenuButton, SplitPane,
   StackedAreaChart, StackedBarChart, StackPane, SubScene, SVGPath,
   SwingNode, Tab, TableCell, TableColumn, TableColumnBase, TableRow,
   TableView, TabPane, Text, TextArea, TextField, TextFieldListCell,
   TextFieldTableCell, TextFieldTreeCell, TextFieldTreeTableCell,
   TextFlow, TextInputControl, TilePane, TitledPane, ToggleButton,
   ToolBar, Tooltip, TreeCell, TreeTableCell, TreeTableColumn,
   TreeTableRow, TreeTableView, TreeView, ValueAxis, VBox, WebView,
   XYChart
   ])

(def window-classes
  [PopupWindow Stage Popup])

(def other-classes
  [TreeItem FileChooser DirectoryChooser ToggleGroup
   RowConstraints ColumnConstraints])

(def animation-classes
  [FadeTransition FillTransition ParallelTransition PathTransition PauseTransition
   RotateTransition ScaleTransition SequentialTransition StrokeTransition TranslateTransition
   Timeline])

(def other-animation-classes
  [KeyFrame KeyValue])

(defn declare-classes [classes]
  (let [symbols (for [c classes]
                  (-> c (.getSimpleName) l/lower-hyphen-symbol))]
    (loop [s "(declare"
           v (first symbols)
           all-rest (rest symbols)]
      (if v
        (if (> (count s) 80)
          (do (println s)
              (recur (str "  " v) (first all-rest) (rest all-rest)))
          (recur (str s " " v) (first all-rest) (rest all-rest)))
        (println s ")")))))

(def base "../../../src/fx_clj")

;; controls
(defn generate-controls []
  (let [controls (concat styleable-classes window-classes other-classes animation-classes)
        f (io/file base "internal/controls.clj")
        s (with-out-str
            (prn '(ns fx-clj.internal.controls))

            (println)
            (println "(def class-names")
            (print "  {")
            (doseq [c controls]
              (let [sym (-> c (.getSimpleName) l/lower-hyphen-keyword)
                    class-name (. c getName)]
                (print (str sym " \"" class-name "\"\n   "))))
            (println "})")
            )]
    (spit f s)))
(generate-controls)

;; ../core.clj
(defn generate-core []
  (let [f (io/file base "core.clj")
        s (with-out-str
            (println "(ns fx-clj.core
  (:refer-clojure :exclude [run!])
  (:require
    [potemkin :refer [import-vars]]
    [fx-clj.core.run]
    [fx-clj.core.pset]
    [fx-clj.hiccup]
    [fx-clj.enlive]
    [fx-clj.elements]
    [fx-clj.css]
    [fx-clj.core.i18n]
    [fx-clj.util]
    [fx-clj.sandbox]
    [fx-clj.core.transforms]
    [fx-clj.core.extensibility]
    [fx-clj.core.binding]
    [clojure.string :as str]))")

            (println)
            (println "; declare styleable-classes")
            (declare-classes styleable-classes)

            (println)
            (println "; declare window-classes")
            (declare-classes window-classes)

            (println)
            (println "; declare other-classes")
            (declare-classes other-classes)

            (println)
            (println "; declare animation-classes")
            (declare-classes animation-classes)

            (println)
            (println "(import-vars
  [fx-clj.core.run run! run<! run<!!]
  [fx-clj.core.pset pset!]
  [fx-clj.hiccup compile-fx build]
  [fx-clj.enlive at!]
  [fx-clj.sandbox sandbox]
  [fx-clj.css set-global-css!]
  [fx-clj.core.i18n with-locale with-resource-bundle
   get-resource-bundle get-locale get-resource]
  [fx-clj.util event-handler callback lookup]
  [fx-clj.core.binding property-ref observable-property bind<- bind<-> bind->])

(defn import-all [ns-sym]
  (eval
    `(potemkin/import-vars
       [~ns-sym
        ~@(keys (ns-publics (find-ns ns-sym)))])))

(import-all 'fx-clj.elements)
(import-all 'fx-clj.core.transforms)

(comment
  (defn available-transforms
    \"Prints information on available transform functions for use
    primarily in the [[at!]] function.\"
    {:doc/format :markdown}
    []
    (doseq [xform @fx-clj.core.extensibility/defined-transforms]
      (let [{:keys [doc]} (meta xform)]
        (println xform)
        (println doc)
        (println))))

  (alter-meta!
    #'fx-clj.core/at!
    update-in [:doc]
    (fn [doc]
      (str doc
           (str/join
             \"\\n\"
             (for [xform @fx-clj.core.extensibility/defined-transforms]
               (let [{:keys [ns name]} (meta xform)]
                 (str \"  [[\" name \"]]\"))))))))")

            )]
    (spit f s)))
(generate-core)